using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace FrameWork.Inventory
{
    [CreateAssetMenu]
    [System.Serializable]
    public class InventorySO : ScriptableObject
    {
        // 临时变量
        public int size = 20;
        //
        public event Action<Dictionary<int, InventoryItem>> OnInventoryUpdate;
        
        private List<InventoryItem> myInventorys;            // 保存物品
        private Dictionary<string, int> itemDic;             // 记录物品的 物品名字 与 在List容器中的序列号
        public List<InventoryItem> GetMyInventorys { get { return myInventorys; } }
        public Dictionary<string, int> GetItemDic { get { return itemDic; } }
        

        // 初始化库存
        public void InventoryInitialize(int size)
        {
            this.size = size;
            // 
            myInventorys = new List<InventoryItem>();
            itemDic = new Dictionary<string, int>();

            for (int i = 0; i < size; i++)
            {
                myInventorys.Add(InventoryItem.GetEmptyInventoryItem());
            }
        }

        public void Init(List<InventoryItem> inventorys, Dictionary<string, int> itemDic)
        {
            myInventorys = inventorys;
            this.itemDic = itemDic;
        }
        
        /// <summary>
        /// 获取当前背包状态
        /// 是否有空位
        /// true，有空位，可存入物品
        /// 存物品之前，必须优先调用该函数进行判断
        /// </summary>
        /// <returns></returns>
        public bool GetInventoryState()
        {
            // 遍历背包
            for (int i = 0; i < myInventorys.Count; i++)
            {
                // 如果存在空值，证明有空位，返回true，退出循环
                if (myInventorys[i].IsEmpty)
                {
                    return true;
                }
            }
            
            return false;
        }

        // 添加物品
        public void AddItem(ItemSO item, int quantity)
        {
            // 如果存在物品
            if (itemDic.ContainsKey(item.ItemName))
            {
                // 获取索引
                int index = itemDic[item.ItemName];
                // 修改数量
                myInventorys[index] = myInventorys[index].ChangeQuantity(myInventorys[index].quantity + quantity);
            }
            else
            {
                // 物品不存在
                for (int i = 0; i < myInventorys.Count; i++)
                {
                    // 物品状态为空
                    if (myInventorys[i].IsEmpty)
                    {
                        // 在该位置添加物品
                        myInventorys[i] = new InventoryItem()
                        {
                            item = item,
                            quantity = quantity
                        };
                        // 更新字典内的键值对 索引
                        itemDic.Add(item.ItemName, i);
                        // 退出循环
                        break;
                    }
                }
            }

            UpdateView();
        }
        
        // 移除物品
        public void RemoveItem(ItemSO item, int quantity)
        {
            // 如果物品不存在，直接返回
            if (!itemDic.ContainsKey(item.ItemName))
                return;

            int index = itemDic[item.ItemName];
            myInventorys[index] = myInventorys[index].ChangeQuantity(myInventorys[index].quantity - quantity);

            // 移除物品后检测物品状态，如果对应物品为空
            if (myInventorys[index].IsEmpty)
            {
                // 广播事件，该物体被移除
                EventSystem.Instance.EventTrigger(EventName.EVENT_INVENTORY_MODEL_ITEMCLEAR, item.ItemName);
                // 将物品设置为null
                myInventorys[index] = InventoryItem.GetEmptyInventoryItem();
                // 移除字典内的键值对索引
                itemDic.Remove(item.ItemName);
            }

            UpdateView();
        }
        
        /// <summary>
        /// 物品排序
        /// </summary>
        public void ItemOrdering()
        {
            Debug.Log("物品排序");
            // 取出所有非空数据
            List<InventoryItem> order = new List<InventoryItem>();
            for (int i = 0; i < size; i++)
            {
                if(!myInventorys[i].IsEmpty)
                    order.Add(myInventorys[i]);
            }
            
            // 使用快速排序，时间复杂度在 O(n log n)
            QuickSort(order, 0, order.Count - 1);
            
            // 更新仓库
            UpdateInventory(order);
    
            // 更新字典
            UpdateDictionary(order);
            
            // 通知UI界面更新
            UpdateView();
        }
        
        // 快速排序实现
        private void QuickSort(List<InventoryItem> items, int left, int right)
        {
            Debug.Log("快速排序实现");
            if (left < right)
            {
                int pivotIndex = Partition(items, left, right);
                QuickSort(items, left, pivotIndex - 1);
                QuickSort(items, pivotIndex + 1, right);
            }
        }

        // 分区操作
        private int Partition(List<InventoryItem> items, int left, int right)
        {
            Debug.Log("分区");
            InventoryItem pivot = items[right];
            int i = left - 1;
    
            for (int j = left; j < right; j++)
            {
                // 排序条件
                if (items[j].quantity > pivot.quantity)
                {
                    i++;
                    Swap(items, i, j);
                }
            }
    
            Swap(items, i + 1, right);
            return i + 1;
        }

        // 交换两个元素
        private void Swap(List<InventoryItem> items, int i, int j)
        {
            (items[i], items[j]) = (items[j], items[i]);
        }
        
        // 更新仓库
        private void UpdateInventory(List<InventoryItem> orderedItems)
        {
            Debug.Log("更新仓库");
            
            // 清空仓库所有数据
            for (int i = 0; i < size; i++)
            {
                myInventorys[i] = InventoryItem.GetEmptyInventoryItem();
            }
            // 填充新的有序物品
            for (int i = 0; i < orderedItems.Count; i++)
            {
                // 在该位置添加物品
                myInventorys[i] = new InventoryItem()
                {
                    item = orderedItems[i].item,
                    quantity = orderedItems[i].quantity
                };
            }
        }

        // 更新字典
        private void UpdateDictionary(List<InventoryItem> orderedItems)
        {
            Debug.Log("更新字典");
            itemDic.Clear();
            for (int i = 0; i < orderedItems.Count; i++)
            {
                itemDic.Add(orderedItems[i].item.ItemName, i);
            }
        }

        /// <summary>
        /// 获取物品
        /// </summary>
        /// <param name="itemName"></param>
        /// <returns></returns>
        public InventoryItem GetItem(string itemName)
        {
            if (itemDic.ContainsKey(itemName))
            {
                int index = itemDic[itemName];
                return myInventorys[index];
            }
            else
            {
                return InventoryItem.GetEmptyInventoryItem();
            }
        }

        /// <summary>
        /// 获取当前库存状态
        /// </summary>
        /// <returns></returns>
        public Dictionary<int, InventoryItem> GetCurrentInventoryItemState()
        {
            Dictionary<int, InventoryItem> result = new Dictionary<int, InventoryItem>();
            for (int i = 0; i < myInventorys.Count; i++)
            {
                if (!myInventorys[i].IsEmpty)
                {
                    result.Add(i, myInventorys[i]);
                }
            }

            return result;
        }
        
        /// <summary>
        /// 获取当前库存状态
        /// </summary>
        /// <returns></returns>
        public List<InventoryItem> GetCurrentInventoryItem()
        {
            List<InventoryItem> result = new List<InventoryItem>();
            for (int i = 0; i < myInventorys.Count; i++)
            {
                if (!myInventorys[i].IsEmpty)
                {
                    result.Add(myInventorys[i]);
                }
            }

            return result;
        }

        /// <summary>
        /// 视图更新
        /// </summary>
        public void UpdateView()
        {
            OnInventoryUpdate?.Invoke(GetCurrentInventoryItemState());
        }
    }

    public struct InventoryItem
    {
        public int quantity;               // 物品数量
        public ItemSO item;
        public bool IsEmpty => quantity <= 0 || item == null;

        public InventoryItem ChangeQuantity(int newQuantity)
        {
            return new InventoryItem()
            {
                item = this.item,
                quantity = newQuantity,
            };
        }

        public static InventoryItem GetEmptyInventoryItem()
        {
            return new InventoryItem()
            {
                item = null,
                quantity = 0,
            };
        }
    }
}